/**
 * 判断一个url是不是有有效的http格式
 * @param { string } url 链接地址
 * @returns { boolean } 是否是一个链接
 * **/
export const isValidUrl = (url: string): boolean => {
    return /^(http|https):\/\//.test(url);
};

/**
 * 获取一个数据的类型
 * @param { unknown } value 需要判断类型的数据
 * @returns { string | null } 判断的数据类型
 * **/
export const getType = (value: unknown): string | null => {
    const typeResult = Object.prototype.toString.call(value);
    const type = typeResult
        .slice(typeResult.indexOf(' ') + 1, -1)
        .toLocaleLowerCase();
    if (type === 'array') {
        if (Array.isArray(value)) return 'array';
        else return null;
    }
    return type;
};

/**
 * 判断一个数据的类型是否为指定的类型
 * @param { unknown } value 需要判断类型的数据
 * @param { string | Array } type 期望的数据类型
 * @return { boolean } 是否为期望的类型
 * **/
export const isType = (
    value: unknown,
    type: string | Array<string>
): boolean => {
    const valueType = getType(value);
    if (valueType === null) throw new Error('invalid value...');
    if (typeof type === 'string') return valueType === type.toLocaleLowerCase();
    return type.map((item) => item.toLocaleLowerCase()).includes(valueType);
};

/**
 * 异步或同步延迟等待一段时间
 * @param { number } timeout 等待时常，默认为 1S钟
 * @param { boolean } sync 是否同步
 * @returns { Promise<boolean> } 异步，是否执行完成
 * **/
export const sleep = (timeout = 1000, sync = false): Promise<boolean> => {
    if (!sync) {
        return new Promise((resolve) => {
            const timer = setTimeout(() => {
                clearTimeout(timer);
                resolve(true);
            }, timeout);
        });
    } else {
        const now = Date.now();
        while (Date.now() - now <= timeout) {
            /* empty */
        }
        return Promise.resolve(true);
    }
};

/**
 * 防抖方法
 * @param { (...rest: Array<unknown>) => unknown } cb 方法
 * @param { number } delay 防抖延迟时常, 默认为: 0
 * @param { boolean } immediate 是否需要立即执行，默认为: false
 * **/
export const debounce = (
    cb: (...rest: Array<unknown>) => unknown,
    delay = 0,
    immediate = false
) => {
    let timer: NodeJS.Timeout | null;
    return function (this: unknown, ...rest: Array<unknown>) {
        clearTimeout(timer as NodeJS.Timeout);
        if (!timer && immediate) cb.apply(this, rest);

        const handler = () => {
            clearTimeout(timer as NodeJS.Timeout);
            timer = null;

            if (!immediate) cb.apply(this, rest);
        };

        timer = setTimeout(handler, delay);
        if (immediate && !timer) cb.apply(this, rest);
    };
};

/**
 * 节流方法
 * @param { (...rest: Array<unknown>) => unknown } cb 方法
 * @param { number } delay 节流延迟时常, 默认值为: 0
 * **/
export const throttle = (
    cb: (...rest: Array<unknown>) => unknown,
    delay = 0
) => {
    let loading = false;
    return function (this: any, ...rest: any) {
        if (!loading) cb.apply(this, rest);
        loading = true;
        const timer = setTimeout(() => {
            clearTimeout(timer);
            loading = false;
        }, delay);
    };
};

/**
 * 查看属性是否存在(原型链方式判断)
 * @param { object } value 需要判断的值
 * @param { string } attr key 值
 * **/
export const hasProperty = (value: object, attr: string) => {
    return Reflect.has(value, attr);
};
